﻿using System;
using System.Net.NetworkInformation;
using System.Reflection;
using Ping.Core;
using log4net;

namespace Ping.Server.Jobs
{
	/// <summary>
	/// Performs a ping-job.
	/// </summary>
	public sealed class PingJob
		: Job
	{
		private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
		private static readonly byte[] Buffer = new byte[32];

		public override Type RequestType
		{
			get { return typeof (PingRequest); }
		}

		public override Type ResultType
		{
			get { return typeof (PingResult); }
		}

		public override string Name
		{
			get { return "Ping"; }
		}

		public override Result Perform(Request request)
		{
			var tmp = (PingRequest) request;

			if (Log.IsDebugEnabled)
				Log.DebugFormat("Performing Ping to {0}, TTL: {1}", tmp.Destination, tmp.Ttl);

			using (var p = new System.Net.NetworkInformation.Ping())
			{
				var options = new PingOptions
				              	{
				              		Ttl = tmp.Ttl,
				              		DontFragment = tmp.DontFragment,
				              	};

				PingReply reply = p.Send(tmp.Destination.Native, (int) tmp.Timeout.TotalMilliseconds, Buffer, options);
				if (reply == null)
					throw new InvalidOperationException("Ping.Send returned null");

				var result = new PingResult
				             	{
				             		Sender = new IpAddress(reply.Address),
				             		Rtt = TimeSpan.FromMilliseconds(reply.RoundtripTime),
				             		Status = (IpStatus) reply.Status,
				             	};

				if (Log.IsDebugEnabled)
					Log.DebugFormat("Ping to {0}: {1}, RTT: {2} ms", reply.Address, reply.Status, reply.RoundtripTime);

				return result;
			}
		}
	}
}